/**
 * Message组件的管理器
 * 负责创建、管理和关闭消息实例
 */

import { App, h, render } from 'vue';
import Message from './Message.vue';
import { TuiMessage, TuiMessageInstance, TuiMessageProps, TuiMessageType } from './types';

// 保存全局Vue应用实例的引用
let globalApp: App | null = null;

/**
 * 设置全局Vue应用实例
 * @param app Vue应用实例
 */
export function setGlobalApp(app: App) {
  globalApp = app;
}

// 消息实例列表
let instances: TuiMessageInstance[] = [];
// 消息id计数器
let seed = 1;

// 存储不同位置的消息容器
const messageContainers: Record<string, HTMLElement> = {};

/**
 * 获取flex布局方向
 * @param placement 消息位置
 * @returns flex布局方向
 */
function getFlexDirection(placement: string): string {
  if (placement.includes('bottom')) {
    return 'column-reverse';
  }
  return 'column';
}

/**
 * 为指定位置创建或获取消息容器
 * @param placement 消息位置
 * @returns 消息容器
 */
export function getReferenceElement(placement: string): HTMLElement {
  if (!messageContainers[placement]) {
    // 创建消息容器
    const container = document.createElement('div');
    container.className = `tui-message-container tui-message-container-${placement}`;
    container.style.position = 'fixed';
    container.style.display = 'flex';
    container.style.flexDirection = getFlexDirection(placement);
    container.style.zIndex = '1999';
    container.style.alignItems = placement.includes('left') ? 'flex-start' : 
                             placement.includes('right') ? 'flex-end' : 'center';
    
    // 根据位置设置容器的位置
    switch (placement) {
      case 'top':
      case 'top-left':
      case 'top-right':
        container.style.top = '0';
        break;
      case 'bottom':
      case 'bottom-left':
      case 'bottom-right':
        container.style.bottom = '0';
        break;
    }

    // 设置水平位置
    if (placement.includes('left')) {
      container.style.left = '0';
    } else if (placement.includes('right')) {
      container.style.right = '0';
    } else {
      // 居中位置
      container.style.left = '50%';
      container.style.transform = 'translateX(-50%)';
    }

    document.body.appendChild(container);
    messageContainers[placement] = container;
  }

  return messageContainers[placement];
}

/**
 * 创建消息实例
 * @param options 消息配置
 */
const createMessage = (options: TuiMessageProps | string): TuiMessageInstance => {
  // 处理字符串类型的配置
  if (typeof options === 'string') {
    options = { message: options };
  }

  // 解构配置项，设置默认值
  const {
    message,
    type = 'info',
    plain = false,
    icon = '',
    dangerouslyUseHTMLString = false,
    customClass = '',
    duration = 3000,
    showClose = false,
    onClose = () => { },
    offset = 16,
    placement = 'top',
    grouping = false,
    repeatNum = 1,
    pushTo = 'top'
  } = options;

  // 检查消息是否可以分组
  if (grouping && typeof message === 'string') {
    const existedInstance = instances.find(
      instance => instance.message === message && instance.type === type && instance.placement === placement
    );

    if (existedInstance) {
      // 更新重复次数
      existedInstance.repeatNum = (existedInstance.repeatNum || 0) + 1;
      
      // 如果有vnode引用，尝试更新组件实例的props以触发UI更新
      if (existedInstance.vnode && existedInstance.vnode.component) {
        (existedInstance.vnode.component.props as TuiMessageProps).repeatNum = existedInstance.repeatNum;
      }
      
      return existedInstance;
    }
  }

  // 生成消息id
  const id = `message_${seed++}`;

  // 创建消息容器
  const container = document.createElement('div');
  container.style.margin = `${offset}px 0`; // 添加垂直边距
  
  // 获取对应位置的消息容器
  const messageContainer = getReferenceElement(placement);
  // 根据pushTo属性决定消息插入位置
  if (pushTo === 'top') {
    messageContainer.insertBefore(container, messageContainer.firstChild);
  } else {
    messageContainer.appendChild(container);
  }

  // 确保有全局app实例
  if (!globalApp) {
    console.error('Message组件需要先初始化全局Vue应用实例');
    return null as unknown as TuiMessageInstance;
  }

  // 创建消息props
  const props: TuiMessageProps = {
    message,
    type,
    plain,
    icon,
    dangerouslyUseHTMLString,
    customClass,
    duration,
    showClose,
    offset,
    placement,
    grouping,
    repeatNum,
    pushTo,
    onClose: () => {
      // 调用用户自定义的onClose回调
      onClose();
      // 移除消息实例
      closeMessage(id);
      // 移除DOM元素
      if (container && container.parentNode) {
        render(null, container);
        container.parentNode.removeChild(container);
      }
    }
  };

  // 创建虚拟节点
  const vnode = h(Message, props);

  // 渲染到容器
  render(vnode, container);

  // 创建消息实例对象
  const instance: TuiMessageInstance = {
    id,
    message,
    type,
    placement,
    offset,
    repeatNum,
    pushTo,
    close: () => {
      closeMessage(id);
      if (container && container.parentNode) {
        render(null, container);
        container.parentNode.removeChild(container);
      }
    },
    // 设置组件实例的根DOM元素
    $el: container,
    // 保存vnode引用
    vnode
  };

  // 添加到实例列表
  instances.push(instance);

  return instance;
};

/**
 * 关闭指定的消息实例
 * @param id 消息id
 */
const closeMessage = (id: string) => {
  const index = instances.findIndex(instance => instance.id === id);
  if (index === -1) return;
  // 从实例列表中移除
  instances.splice(index, 1);
};

/**
 * 关闭所有消息实例
 */
const closeAll = () => {
  // 保存所有实例的close方法
  const closes = instances.map(instance => instance.close);
  // 清空实例列表
  instances = [];
  // 执行所有关闭操作
  closes.forEach(close => close());
  
  // 清空所有消息容器
  Object.values(messageContainers).forEach(container => {
    if (container.parentNode) {
      container.parentNode.removeChild(container);
    }
  });
  // 重置消息容器对象
  Object.keys(messageContainers).forEach(key => {
    delete messageContainers[key];
  });
};

/**
 * 创建特定类型的消息
 * @param type 消息类型
 * @param options 消息配置
 */
const createMessageByType = (type: TuiMessageType) => {
  return (options: TuiMessageProps | string) => {
    if (typeof options === 'string') {
      return createMessage({ message: options, type });
    } else {
      return createMessage({ ...options, type });
    }
  };
};

// 创建TuiMessage对象
const message: TuiMessage = createMessage as TuiMessage;

// 添加不同类型的消息方法
message.success = createMessageByType('success');
message.warning = createMessageByType('warning');
message.info = createMessageByType('info');
message.error = createMessageByType('error');
message.closeAll = closeAll;

// 初始化函数
const init = () => {
  // 将消息管理器挂载到window对象上，方便组件访问
  if (typeof window !== 'undefined') {
    (window as any).$tuiMessageManager = {
      getReferenceElement,
      closeAll
    };
  }
};

export { createMessage, closeMessage, closeAll, init };

export default message;